////
// @file table.cc
// @brief
// 实现存储管理
//
// @author niexw
// @email niexiaowen@uestc.edu.cn
//
#include "db/btree.h"

#include <db/table.h>

namespace db {

Table::BlockIterator::BlockIterator()
    : bufDesc(nullptr)
{}
Table::BlockIterator::~BlockIterator()
{
    if (bufDesc) kBuffer.releaseBuf(bufDesc);
}
Table::BlockIterator::BlockIterator(const BlockIterator &other)
    : block(other.block)
    , bufDesc(other.bufDesc)
{
    if (bufDesc) bufDesc->addRef();
}

// 前置操作
Table::BlockIterator &Table::BlockIterator::operator++()
{
    if (block.buffer_ == nullptr) return *this;
    unsigned int blockid = block.getNext();
    kBuffer.releaseBuf(bufDesc);
    if (blockid) {
        bufDesc = kBuffer.borrow(block.table_->name_.c_str(), blockid);
        block.attach(bufDesc->buffer);
    } else
        block.buffer_ = nullptr;
    return *this;
}
// 后置操作
Table::BlockIterator Table::BlockIterator::operator++(int)
{
    BlockIterator tmp(*this);
    if (block.buffer_ == nullptr) return *this;
    unsigned int blockid = block.getNext();
    kBuffer.releaseBuf(bufDesc);
    if (blockid) {
        bufDesc = kBuffer.borrow(block.table_->name_.c_str(), blockid);
        block.attach(bufDesc->buffer);
    } else
        block.buffer_ = nullptr;
    return tmp;
}
// 数据块指针
DataBlock *Table::BlockIterator::operator->() { return &block; }
void Table::BlockIterator::release()
{
    bufDesc->relRef();
    block.detach();
}

Table::RecordIterator::RecordIterator() {}
Table::RecordIterator::~RecordIterator()
{
    blockIt.~BlockIterator();
}
Table::RecordIterator::RecordIterator(const Table::RecordIterator &other):
    index(other.index),
    blockIt(other.blockIt)
{}
void Table::RecordIterator::attach(Table * newTable){
    blockIt.block.table_ = newTable;
}

Table::RecordIterator &Table::RecordIterator::operator++() {
    if (blockIt->buffer_ == nullptr || blockIt->getSlots() == 0) {
        index = 0;
        blockIt->buffer_ = nullptr;
        return *this;
    }
    bool flag = true;
    while (blockIt != blockIt.block.table_->endBlock()) {
        if (index + flag < blockIt->getSlots()) {
            // 继续在当前block上
            index += flag;
            Slot *slot = blockIt->getSlotsPointer();
            record.attach(
                blockIt->buffer_ + be16toh(slot[index].offset),
                be16toh(slot[index].length)
                );
            return *this;
        }
        // 进入下一个block
        flag = false;
        ++blockIt;
        index = 0;
    }
    // 到达末尾
    blockIt.~BlockIterator();
    record.detach();
    index = 0;
    return *this;
}
Table::RecordIterator Table::RecordIterator::operator++(int) {
    Table::RecordIterator tmp(*this);
    if (blockIt->buffer_ == nullptr || blockIt->getSlots() == 0) {
        index = 0;
        return *this;
    }
    bool flag = true;
    while (blockIt != blockIt.block.table_->endBlock()) {
        if (index + flag < blockIt->getSlots()) {
            // 继续在当前block上
            index += flag;
            Slot *slot = blockIt->getSlotsPointer();
            record.attach(
                blockIt->buffer_ + be16toh(slot[index].offset),
                be16toh(slot[index].length)
                );
            return tmp;
        }
        // 进入下一个block
        flag = false;
        ++blockIt;
        index = 0;
    }
    // 到达末尾
    blockIt.~BlockIterator();
    record.detach();
    return tmp;
}
Table::RecordIterator &Table::RecordIterator::operator+=(int step) {
    if (blockIt->buffer_ == nullptr || blockIt->getSlots() == 0) return *this;
    while (step-- > 0) {
        ++(*this);
    }
    return *this;
}
Record *Table::RecordIterator::operator->() {
    return &record;
}

int Table::open(const char *name)
{
    // 查找table
    std::pair<Schema::TableSpace::iterator, bool> bret = kSchema.lookup(name);
    if (!bret.second) return EEXIST; // 表不存在

    // 填充结构
    name_ = name;
    info_ = &bret.first->second;

    // 加载超块
    SuperBlock super;
    BufDesc *desc = kBuffer.borrow(name, 0);
    super.attach(desc->buffer);

    // 获取元数据
    maxid_ = super.getMaxId();
    idle_ = super.getIdle();
    first_ = super.getFirst();

    // 释放超块
    super.detach();
    desc->relRef();
    return S_OK;
}

unsigned int Table::allocate()
{
    // 空闲链上有block
    DataBlock data;
    SuperBlock super;
    BufDesc *desc;

    if (idle_) {
        // 读idle块，获得下一个空闲块
        desc = kBuffer.borrow(name_.c_str(), idle_);
        data.attach(desc->buffer);
        unsigned int next = data.getNext();
        data.detach();
        desc->relRef();

        // 读超块，设定空闲块
        desc = kBuffer.borrow(name_.c_str(), 0);
        super.attach(desc->buffer);
        super.setIdle(next);
        super.setIdleCounts(super.getIdleCounts() - 1);
        super.setDataCounts(super.getDataCounts() + 1);
        super.setChecksum();
        super.detach();
        kBuffer.writeBuf(desc);
        desc->relRef();

        unsigned int current = idle_;
        idle_ = next;

        desc = kBuffer.borrow(name_.c_str(), current);
        data.attach(desc->buffer);
        data.clear(1, current, BLOCK_TYPE_DATA);
        desc->relRef();

        return current;
    }

    // 没有空闲块
    ++maxid_;
    // 读超块，设定空闲块
    desc = kBuffer.borrow(name_.c_str(), 0);
    super.attach(desc->buffer);
    super.setMaxId(maxid_);
    super.setDataCounts(super.getDataCounts() + 1);
    super.setChecksum();
    super.detach();
    kBuffer.writeBuf(desc);
    desc->relRef();
    // 初始化数据块
    desc = kBuffer.borrow(name_.c_str(), maxid_);
    data.attach(desc->buffer);
    data.clear(1, maxid_, BLOCK_TYPE_DATA);
    desc->relRef();

    return maxid_;
}

void Table::deallocate(unsigned int blockid)
{
    // 读idle块，获得下一个空闲块
    DataBlock data;
    BufDesc *desc = kBuffer.borrow(name_.c_str(), blockid);
    data.attach(desc->buffer);
    data.setNext(idle_);
    data.setChecksum();
    data.detach();
    kBuffer.writeBuf(desc);
    desc->relRef();

    // 读超块，设定空闲块
    SuperBlock super;
    desc = kBuffer.borrow(name_.c_str(), 0);
    super.attach(desc->buffer);
    super.setIdle(blockid);
    super.setIdleCounts(super.getIdleCounts() + 1);
    super.setDataCounts(super.getDataCounts() - 1);
    super.setChecksum();
    super.detach();
    kBuffer.writeBuf(desc);
    desc->relRef();

    // 设定自己
    idle_ = blockid;
}

Table::BlockIterator Table::beginBlock()
{
    // 通过超块找到第1个数据块的id
    BlockIterator bi;
    bi.block.table_ = this;

    // 获取第1个blockid
    BufDesc *bd = kBuffer.borrow(name_.c_str(), 0);
    SuperBlock super;
    super.attach(bd->buffer);
    unsigned int blockid = super.getFirst();
    kBuffer.releaseBuf(bd);

    bi.bufDesc = kBuffer.borrow(name_.c_str(), blockid);
    bi.block.attach(bi.bufDesc->buffer);
    return bi;
}

Table::BlockIterator Table::endBlock()
{
    BlockIterator bi;
    bi.block.table_ = this;
    return bi;
}

unsigned int Table::locate(void *keyBuf, unsigned int len)
{
    unsigned int key = info_->key;
    DataType *type = info_->fields[key].type;

    BlockIterator prev = beginBlock();
    for (BlockIterator bi = beginBlock(); bi != endBlock(); ++bi) {
        // 获取第1个记录
        Record record;
        bi->refSlots(0, record);

        // 与参数比较
        unsigned char *pkey;
        unsigned int kLen;
        record.refByIndex(&pkey, &kLen, key);
        bool bret = type->less(pkey, kLen, static_cast<unsigned char *>(keyBuf), len);
        if (bret) {
            prev = bi;
            continue;
        }
        // 要排除相等的情况
        bret = type->less(static_cast<unsigned char *>(keyBuf), len, pkey, kLen);
        if (bret)
            return prev->getSelf(); //
        return bi->getSelf(); // 相等
    }
    return prev->getSelf();
}

unsigned int Table::locateBTree(void *keyBuf, unsigned int len)
{
    // 通过B树查找
    BTree btree(this);
    std::stack<unsigned short> path;
    if (!btree.search(keyBuf, len, nullptr, &path)) {
        return 0; // 没有找到
    }
    return !path.empty() ? path.top() : 0; // 返回最后一个节点的id
}

int Table::insert(unsigned int blkId, const std::vector<struct iovec> &iov)
{
    DataBlock data;
    SuperBlock super;
    data.setTable(this);

    // 从buffer中借用
    BufDesc *bd = kBuffer.borrow(name_.c_str(), blkId);
    data.attach(bd->buffer);
    // 尝试插入
    std::pair<bool, unsigned short> ret = data.insertRecord(iov);
    if (ret.first) {
        kBuffer.releaseBuf(bd); // 释放buffer
        // 修改表头统计
        bd = kBuffer.borrow(name_.c_str(), 0);
        super.attach(bd->buffer);
        super.setRecords(super.getRecords() + 1);
        bd->relRef();
        return S_OK; // 插入成功
    }
    if (ret.second == static_cast<unsigned short>(-1)) {
        kBuffer.releaseBuf(bd); // 释放buffer
        return EEXIST;          // key已经存在
    }

    // 分裂block
    unsigned short insert_position = ret.second;
    std::pair<unsigned short, bool> split_position =
        data.splitPosition(Record::size(iov), insert_position);
    // 先分配一个block
    DataBlock next;
    next.setTable(this);
    blkId = allocate();
    BufDesc *bd2 = kBuffer.borrow(name_.c_str(), blkId);
    next.attach(bd2->buffer);

    // 移动记录到新的block上
    while (data.getSlots() > split_position.first) {
        Record record;
        data.refSlots(split_position.first, record);
        // TODO: 表达式结果未使用
        next.copyRecord(record);
        data.deallocate(split_position.first);
    }
    // 插入新记录，不需要再重排顺序
    if (split_position.second)
        // TODO: 表达式结果未使用
        data.insertRecord(iov);
    else
        // TODO: 表达式结果未使用
        next.insertRecord(iov);
    // 维持数据链
    next.setNext(data.getNext());
    data.setNext(next.getSelf());
    bd2->relRef();

    bd = kBuffer.borrow(name_.c_str(), 0);
    super.attach(bd->buffer);
    super.setRecords(super.getRecords() + 1);
    bd->relRef();
    return S_OK;
}

int Table::insert(const std::vector<struct iovec> &iov) {
    BTree btree(this);
    if (btree.search(iov[info_->key].iov_base, static_cast<unsigned int>(iov[info_->key].iov_len), nullptr, nullptr)) {
        return EEXIST; // key已经存在
    }
    btree.insert(iov); // 插入记录
    return S_OK;
}

int Table::update(const unsigned int blkId,
    const std::vector<struct iovec> &iov) {
    DataBlock data;
    data.setTable(this);

    // 从buffer中借用
    BufDesc *bd = kBuffer.borrow(name_.c_str(), blkId);
    data.attach(bd->buffer);
    // 查找记录
    bool result = data.updateRecord(iov);
    kBuffer.releaseBuf(bd); // 释放buffer
    if (result) {
        return S_OK; // 更新成功
    }
    // 更新失败，可能是key不匹配
    return ENOENT;
}

int Table::update(const std::vector<struct iovec> &iov) {
    unsigned int key = info_->key;
    // 查找记录
    unsigned int blkId = locateBTree(iov[key].iov_base, static_cast<unsigned int>(iov[key].iov_len));
    if (blkId == 0) return ENOENT; // 没有找到记录
    // 更新记录
    BTree btree(this);
    btree.update(iov);
    return S_OK; // 更新成功
}

int Table::remove(unsigned int blkId, void *keyBuf, unsigned int len) { // NOLINT(*-use-trailing-return-type)
    DataBlock data;
    SuperBlock super;
    data.setTable(this);

    // 从buffer中借用
    BufDesc *bd = kBuffer.borrow(name_.c_str(), blkId);
    data.attach(bd->buffer);

    // 查找记录
    if (!data.removeRecord(keyBuf, len)) {
        kBuffer.releaseBuf(bd); // 释放buffer
        return ENOENT;          // 没有找到记录
    }
    kBuffer.releaseBuf(bd); // 释放buffer
    // 修改表头统计
    bd = kBuffer.borrow(name_.c_str(), 0);
    super.attach(bd->buffer);
    super.setRecords(super.getRecords() - 1);
    bd->relRef();
    kBuffer.releaseBuf(bd);
    return S_OK; // 删除成功
}

int Table::remove(void *keyBuf, unsigned int len) {
    unsigned int key = info_->key;
    // 查找记录
    unsigned int blkId = locate(keyBuf, len);
    if (blkId == 0) return ENOENT; // 没有找到记录
    // 删除记录
    BTree btree(this);
    btree.remove(keyBuf, len);
    return S_OK; // 删除成功
}

Table::RecordIterator Table::beginRecord() {
    BlockIterator bi = beginBlock();
    RecordIterator ri;
    ri.attach(this);
    ri.blockIt = bi;
    ri.index = 0;
    if (bi.block.buffer_ == nullptr || bi.block.getSlots() == 0) {
        ri.record.detach();
        return ri; // 没有记录
    }
    Slot *slots = bi.block.getSlotsPointer();
    ri.record.attach(
        bi.block.buffer_ + be16toh(slots[0].offset),
        be16toh(slots[0].length));
    return ri;
}

Table::RecordIterator Table::endRecord() {
    BlockIterator bi = endBlock();
    RecordIterator ri;
    ri.attach(this);
    ri.blockIt = bi;
    ri.index = 0; // 末尾的index为0
    ri.record.detach(); // 末尾的record不需要引用
    return ri;
}

size_t Table::recordCount() const
{
    BufDesc *bd = kBuffer.borrow(name_.c_str(), 0);
    SuperBlock super;
    super.attach(bd->buffer);
    size_t count = super.getRecords();
    kBuffer.releaseBuf(bd);
    return count;
}

unsigned int Table::dataCount() const
{
    BufDesc *bd = kBuffer.borrow(name_.c_str(), 0);
    SuperBlock super;
    super.attach(bd->buffer);
    unsigned int count = super.getDataCounts();
    kBuffer.releaseBuf(bd);
    return count;
}

unsigned int Table::idleCount() const
{
    BufDesc *bd = kBuffer.borrow(name_.c_str(), 0);
    SuperBlock super;
    super.attach(bd->buffer);
    unsigned int count = super.getIdleCounts();
    kBuffer.releaseBuf(bd);
    return count;
}

} // namespace db
